﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace YATC
{
   public class GameMatrix : DrawableGameComponent
    {
       private Cell[,] _matrix;
       private const int LMax = 19;
       private const int CMax = 10;
       private TimeSpan time = TimeSpan.Zero;
       private Piece piece;
       private int keyTime, keyTimeh;TimeSpan tranTime = TimeSpan.Zero;
       private int keyTimeR, keyTimehR;
       private int keyTimeU, keyTimehU;
       private int keyTimeS, keyTimehS;
       private bool isGameOver;
       private Random rando;
       private Model bord;
       private bool first = true;
       private Matrix view;
       private float rot;
       private Matrix gameWorldRotation = Matrix.Identity;
       private Model[] nPieces;
       private int nc,cc;
       private Model goText,gpText;
       private bool translate;
       private int tline = LMax - 1;
       private bool up = true, down;
       private Matrix _gameWorldRotation = Matrix.Identity;
       private float _rot;
       private bool pause;
       private KeyboardState oldS;
       //Audio stuff
       private AudioLibrary audio;

       public GameMatrix(Game game, Model model, List<GameComponent> list, Model Bord, Model[] nPieces, Model goText, Model gpText)
           : base(game)
       {
           _matrix = new Cell[LMax,CMax];
           bord = Bord;
           this.nPieces = nPieces;
           rando = new Random();
           nc = rando.Next(10);
           this.goText = goText;
           this.gpText = gpText;

           var p = new Vector3(-12f, 12, 0);
           var s = 1f;
           for (int i = 0; i < LMax; i++)
           {
               p.Y -= 1.1f;
               for (int j = 0; j < CMax; j++)
               {
                   p.X += 1.1f;
                   var m = model;
                   _matrix[i, j] = new Cell(Game, m, s, p, ((Game1) Game)._text);
                   list.Add(_matrix[i, j]);
               }
               p.X = -12;
           }
       }

       public override void Initialize()
       {
           audio = (AudioLibrary)Game.Services.GetService(typeof(AudioLibrary));

           MediaPlayer.Stop();
           MediaPlayer.Play(audio.GetNextMusic());

           oldS = Keyboard.GetState();

           for (int i = 0; i < LMax; i++)
           {
               for (int j = 0; j < CMax; j++)
               {
                   _matrix[i,j].Initialize();
               }
           }

           piece = new Piece();
           var r = rando.Next(10);
           for (int i = 0; i < piece.List.Count; i++)
           {
               if (piece.List[i].Y > -1)
               {
                   _matrix[(int)piece.List[i].Y, (int)piece.List[i].X].Status = CellStatus.Buzy;
                   _matrix[(int)piece.List[i].Y, (int)piece.List[i].X].CoLor = r;
               }
           }

           keyTime = 0;
           keyTimeR = 0;
           keyTimeS = 0;
           keyTimeU = 0;
           time = TimeSpan.Zero;
           tranTime = TimeSpan.Zero;

           keyTimeh = Environment.TickCount;
           keyTimehU = Environment.TickCount;
           keyTimehS = Environment.TickCount;
           keyTimehR = Environment.TickCount;
           isGameOver = false;
           gameWorldRotation = Matrix.Identity;
           _gameWorldRotation = Matrix.Identity;

           Score.score = 0;
           Score.level = 1;
           Score.lines = (int)((float)(Score.level * 5) / 1.6f + 2.5f);
           Score.speed = 500;

           translate = false;

           base.Initialize();
       }
       public override void Update(GameTime gameTime)
       {
           if (!isGameOver && !translate)
           {

               _rot += 1.1f;
               _gameWorldRotation = Matrix.CreateRotationX(MathHelper.ToRadians(_rot));
               var curS = Keyboard.GetState();

               if (curS.IsKeyDown(Keys.P) && oldS.IsKeyUp(Keys.P))
                   pause = !pause;

               oldS = curS;
           }
           if (!pause)
           {
               
               if (isGameOver)
               {
                   _rot += 1.1f;
                   _gameWorldRotation = Matrix.CreateRotationX(MathHelper.ToRadians(_rot));
               }
               if (!translate)
               {
                   rot += 1.1f;

                   gameWorldRotation = Matrix.CreateRotationY(MathHelper.ToRadians(rot));

                   if (Score.lines <= 0)
                       Score.lines = 0;

                   keyTime = Environment.TickCount - keyTimeh;
                   keyTimeR = Environment.TickCount - keyTimehR;
                   keyTimeU = Environment.TickCount - keyTimehU;
                   keyTimeS = Environment.TickCount - keyTimehS;
                   time += gameTime.ElapsedGameTime;
                   //Naechstes level?
                   if (IsNewLevel())
                   {
                       translate = true;
                   }
                   //Lines geschafft?
                   ClearLines();
                   //neuer Block?
                   if (IsNewBlock())
                   {
                      piece.GenerateNewBlock();
                       //Game Over?
                       if (!IsGameOver())
                       {
                           cc = nc;
                           nc = rando.Next(10);
                           for (int i = 0; i < piece.List.Count; i++)
                           {
                               if (piece.List[i].Y > -1)
                               {
                                   _matrix[(int) piece.List[i].Y, (int) piece.List[i].X].Status = CellStatus.Buzy;
                                   _matrix[(int) piece.List[i].Y, (int) piece.List[i].X].CoLor = cc;

                               }
                           }
                       }
                       else
                           isGameOver = true;
                   }

                   if (!isGameOver)
                   {

                       if (time > TimeSpan.FromMilliseconds(Score.speed))
                       {
                           if (CanMoveDown())
                               MoveDown();
                           time -= TimeSpan.FromMilliseconds(Score.speed);
                       }

                       if (Keyboard.GetState().IsKeyDown(Keys.Left))
                       {
                           if (keyTime > 100)
                           {
                               if (CanMoveLeft())
                                   MoveLeft();
                               keyTimeh = System.Environment.TickCount;
                           }
                       }
                       if (Keyboard.GetState().IsKeyDown(Keys.Right))
                       {
                           if (keyTimeR > 100)
                           {
                               if (CanMoveRight())
                                   MoveRight();
                               keyTimehR = System.Environment.TickCount;
                           }
                       }
                       if (Keyboard.GetState().IsKeyDown(Keys.Up))
                       {
                           if (keyTimeU > 200)
                           {
                               if (CanRotate())
                                   Rotate();
                               keyTimehU = System.Environment.TickCount;
                           }
                       }
                       if (Keyboard.GetState().IsKeyDown(Keys.Space))
                       {
                           if (keyTimeS > 50)
                           {
                               if (CanMoveDown())
                                   MoveDown();
                               keyTimehS = System.Environment.TickCount;
                           }
                       }
                       if (Keyboard.GetState().IsKeyDown(Keys.Down))
                       {
                           if (keyTimeS > 50)
                           {
                               if (CanMoveDown())
                                   MoveDown();
                               keyTimehS = System.Environment.TickCount;
                           }
                       }
                   }
               }
               if (translate)
               {
                   tranTime += gameTime.ElapsedGameTime;
                   if (tranTime > TimeSpan.FromMilliseconds(100))
                   {
                       tranTime -= TimeSpan.FromMilliseconds(100);
                       Traslate();
                   }
               }

               base.Update(gameTime);
           }
       }

       private void Traslate()
       {
           if (up)
           {
               for (int j = 0; j < CMax; j++)
               {
                   _matrix[tline, j].Status = CellStatus.Rotate;
                   _matrix[tline, j].CoLor = 11;
               }
               tline--;
           }
           if(tline == -1)
           {
               up = false;
               down = true;
               tline++;
           }
           if(down)
           {
               for (int j = 0; j < CMax; j++)
               {
                   _matrix[tline, j].Status = CellStatus.Free;
               }
               tline++;

           }
           if(tline == LMax)
           {
               Score.level++;
               Score.lines = (int)(Score.level * 5 / 1.6f + 2.5f);
               if (Score.speed > 80)
                   Score.speed -= 60;

               tline = LMax - 1;
               up = true;
               down = false;
               translate = false;
               
           }

       }
      

       private bool IsNewLevel()
       {
           return Score.lines == 0;
       }
      private void MoveDown()
      {
          int c = _matrix[(int) piece.List[0].Y, (int) piece.List[0].X].CoLor;
          for (int i = 0; i < piece.List.Count; i++)
              if (piece.List[i].Y > -1)
              {
                  _matrix[(int)piece.List[i].Y, (int)piece.List[i].X].Status = CellStatus.Free;
                  _matrix[(int) piece.List[i].Y, (int) piece.List[i].X].CoLor = -1;

              }
          for (int i = 0; i < piece.List.Count; i++)
          {
              var tmp = piece.List[i];
              tmp.Y++;
              piece.List[i] = tmp;
              if (piece.List[i].Y > -1)
              {
                  _matrix[(int)piece.List[i].Y, (int)piece.List[i].X].CoLor = c;
                  _matrix[(int)piece.List[i].Y, (int)piece.List[i].X].Status = CellStatus.Buzy;
              }
          }
      }
     private void MoveRight()
     {
         var c = _matrix[(int) piece.List[0].Y, (int) piece.List[0].X].CoLor;
         for (int i = 0; i < piece.List.Count; i++)
             if (piece.List[i].Y > -1)
             {
                 _matrix[(int) piece.List[i].Y, (int) piece.List[i].X].Status = CellStatus.Free;
                 _matrix[(int) piece.List[i].Y, (int) piece.List[i].X].CoLor = -1;

             }
         for (int i = 0; i < piece.List.Count; i++)
         {
             var tmp = piece.List[i];
             tmp.X++;
             piece.List[i] = tmp;
             if (piece.List[i].Y > -1)
             {
                 _matrix[(int)piece.List[i].Y, (int)piece.List[i].X].Status = CellStatus.Buzy;
                 _matrix[(int) piece.List[i].Y, (int) piece.List[i].X].CoLor = c;
             }
         }
                      
         
     }
      private void MoveLeft()
      {
          var c = _matrix[(int)piece.List[0].Y, (int)piece.List[0].X].CoLor;
          for (int i = 0; i < piece.List.Count; i++)
              if (piece.List[i].Y > -1)
              {
                  _matrix[(int) piece.List[i].Y, (int) piece.List[i].X].Status = CellStatus.Free;
                  _matrix[(int) piece.List[i].Y, (int) piece.List[i].X].CoLor = -1;

              }

          for (int i = 0; i < piece.List.Count; i++)
          {
              var tmp = piece.List[i];
              tmp.X--;
              piece.List[i] = tmp;
              if (piece.List[i].Y > -1)
              {
                  _matrix[(int)piece.List[i].Y, (int)piece.List[i].X].Status = CellStatus.Buzy;
                  _matrix[(int) piece.List[i].Y, (int) piece.List[i].X].CoLor = c;
              }
          }
      }
       private bool CanMoveRight()
       {
           for (int i = 0; i < piece.List.Count; i++)
           {
               if (piece.List[i].X == CMax - 1)
                   return false;
               if (piece.List[i].Y > -1)
                   if (_matrix[(int)piece.List[i].Y, (int)(piece.List[i].X + 1)].Status == CellStatus.Frozed)
                       return false;
           }
           return true;
       }
       private bool CanMoveLeft()
       {
           for (int i = 0; i < piece.List.Count; i++)
           {
               if (piece.List[i].X == 0)
                   return false;
               if (piece.List[i].Y > -1)
                   if (_matrix[(int)piece.List[i].Y, (int)(piece.List[i].X - 1)].Status == CellStatus.Frozed)
                       return false;
           }
           return true;
       }
       private bool CanMoveDown()
       {
           for (int i = 0; i < piece.List.Count; i++)
           {
               if (piece.List[i].Y > -1)
                   if (piece.List[i].Y == LMax - 1 || _matrix[(int)piece.List[i].Y + 1, (int)piece.List[i].X].Status == CellStatus.Frozed)
                   {
                       for (int j = 0; j < piece.List.Count; j++)
                       {
                           if (piece.List[j].Y > -1)
                               _matrix[(int) piece.List[j].Y, (int) piece.List[j].X].Status = CellStatus.Frozed;
                       }

                       return false;
                   }
           }
           return true;
       }
       private bool IsNewBlock()
       {
           for (int i = 0; i < LMax; i++)
               for (int j = 0; j < CMax; j++)
                   if (_matrix[i, j].Status == CellStatus.Buzy)
                       return false;
           return true;
       }
       private bool IsGameOver()
       {
           for (int i = 0; i < piece.List.Count; i++)
           {
               if (piece.List[i].Y > -1)
                   if (_matrix[(int)piece.List[i].Y, (int)piece.List[i].X].Status == CellStatus.Frozed)
                       return true;
           }
           return false;
       }
       public bool _IsGameOver
       {
           get{ return isGameOver;}
       }
       public bool _IsGamePaused
       {
           get{ return pause;}
       }
       public override void Draw(GameTime gameTime)
       { 
           if (first)
           {
               view = ((Game1)Game).camera.ViewMatrix;
               first = false;
           }
         if(isGameOver)
         {
             var __transforms = new Matrix[goText.Bones.Count];
             goText.CopyAbsoluteBoneTransformsTo(__transforms);

             foreach (ModelMesh mesh in goText.Meshes)
             {
                 foreach (BasicEffect effect in mesh.Effects)
                 {
                     effect.EnableDefaultLighting();

                     effect.View = view;
                     effect.Projection = ((Game1)Game).camera.projectionMatrix;
                     effect.World = _gameWorldRotation *Matrix.CreateRotationY(MathHelper.ToRadians(180))*
                                    __transforms[mesh.ParentBone.Index] *
                                    Matrix.CreateTranslation(new Vector3(8f, 0f, 6f));
                 }
                 mesh.Draw();
             }
         }
          
           if (!isGameOver )
               DrawModel(nPieces[piece.GetNextPiece()],piece.GetNextPiece());

          if(!isGameOver && pause)
          {
              var __transforms = new Matrix[gpText.Bones.Count];
             gpText.CopyAbsoluteBoneTransformsTo(__transforms);

             foreach (ModelMesh mesh in gpText.Meshes)
             {
                 foreach (BasicEffect effect in mesh.Effects)
                 {
                     effect.EnableDefaultLighting();

                     effect.View = view;
                     effect.Projection = ((Game1)Game).camera.projectionMatrix;
                     effect.World = _gameWorldRotation *Matrix.CreateRotationY(MathHelper.ToRadians(180))*
                                    __transforms[mesh.ParentBone.Index] *
                                    Matrix.CreateTranslation(new Vector3(8f, 0f, 3f));
                 }
                 mesh.Draw();
             }
          }
            //RahmenN
            var transforms = new Matrix[bord.Bones.Count];
            bord.CopyAbsoluteBoneTransformsTo(transforms);

            foreach (ModelMesh mesh in bord.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.EnableDefaultLighting();
                    //effect.TextureEnabled = true;
                    //effect.Texture = ((Game1) Game)._text[4];
                    
                    effect.View = ((Game1) Game).camera.ViewMatrix;
                    effect.Projection = ((Game1) Game).camera.projectionMatrix;
                    effect.World = Matrix.Identity*
                                   transforms[mesh.ParentBone.Index]*
                                   Matrix.CreateTranslation(new Vector3(0.2f,-13f,0f));
                }
                mesh.Draw();
            }
        
           
           
           
           base.Draw(gameTime);
       }
       public bool Translate
       {
           get{ return translate;}
       }
       private void DrawModel(Model m,int mo)
       {
           Vector3 v;
           switch(mo)
           {
               case 0:
                   v = new Vector3(15.9f, 12.4f, 0);
                   break;
               case 1:
                   v = new Vector3(15.8f, 12.4f, 0);
                   break;
               case 3:
                   v = new Vector3(15.8f, 11.5f, 0);
                   break;
               case 5:
                   v = new Vector3(15.8f, 12.6f, 0);
                   break;
               case 6:
                   v = new Vector3(15.8f, 12.6f, 0);
                   break;
               default:
                   v = new Vector3(15.8f, 12f, 0);
                   break;
           }
           var transforms = new Matrix[m.Bones.Count];
           m.CopyAbsoluteBoneTransformsTo(transforms);

           foreach (ModelMesh mesh in m.Meshes)
           {
               foreach (BasicEffect effect in mesh.Effects)
               {
                   effect.EnableDefaultLighting();
                   effect.TextureEnabled = true;
                   effect.Texture = ((Game1)Game)._text[nc];


                   effect.View = view;
                   effect.Projection = ((Game1)Game).camera.projectionMatrix;
                   effect.World = gameWorldRotation *
                                  transforms[mesh.ParentBone.Index] *
                                  Matrix.CreateTranslation(v)*Matrix.CreateScale(0.8f);
               }
               mesh.Draw();
           }
       }

       private void Rotate()
       {
           var c = _matrix[(int)piece.List[0].Y, (int)piece.List[0].X].CoLor;

           for (int i = 0; i < piece.List.Count; i++)
           {
               if (piece.List[i].Y > -1)
               {
                   _matrix[(int) piece.List[i].Y, (int) piece.List[i].X].Status = CellStatus.Free;
                   _matrix[(int) piece.List[i].Y, (int) piece.List[i].X].CoLor = -1;

               }
           }

		int TmpX,TmpY;
		for(int i = 0; i < piece.List.Count; i++)
		{
		    TmpX =(int)(piece.List[i].X - piece.List[0].X);
			TmpY =(int)(piece.List[i].Y - piece.List[0].Y);
		    var t = piece.List[i];
			t.X = piece.List[0].X + TmpY;
			t.Y = piece.List[0].Y - TmpX;
		    piece.List[i] = t;

            _matrix[(int)piece.List[i].Y, (int)piece.List[i].X].Status = CellStatus.Buzy;
		    _matrix[(int) piece.List[i].Y, (int) piece.List[i].X].CoLor = c;
		}
       }
       private bool CanRotate()
       {
           if (piece.Caro)
               return false;
           int TmpX,TmpY;
           for (int i = 0; i < piece.List.Count; i++)
           {
               TmpX = (int) (piece.List[i].X - piece.List[0].X);
               TmpY = (int) (piece.List[i].Y - piece.List[0].Y);
               if (piece.List[0].Y - TmpX < 0 || piece.List[0].X + TmpY < 0 || piece.List[0].X + TmpY >= CMax || piece.List[0].Y - TmpX >= LMax)
                   return false;
               if(_matrix[(int)(piece.List[0].Y - TmpX),(int)(piece.List[0].X+TmpY)].Status == CellStatus.Frozed)
                   return false;
           }
           return true;
       }
       private void ClearLines()
       {
           bool play = false;
           var line = 0;
           for (int i = 0; i < LMax; i++)
           {
               int count = 0;
               for (int j = 0; j < CMax; j++)
               {
                   if (_matrix[i, j].Status == CellStatus.Frozed)
                       count++;
               }
               if (count == CMax)
               {
                   DeleteLine(i);
                   line++;
                   Score.lines--;
                   play = true;   
               }
           }
           if(play)
           {
               //play sound
               audio.ClearLine.Play();
               audio.ClearLine.Play();
               audio.ClearLine.Play();

           }
           switch(line)
           {
               case 1:
                   {
                       Score.score += (Score.level + 1) * 40;
                       break;
                   }
               case 2:
                   {
                       Score.score += (Score.level + 1) * 100;
                       break;
                   }
               case 3:
                   {
                       Score.score += (Score.level + 1) * 300;
                       break;
                   }
               case 4:
                   {
                       Score.score += (Score.level + 1) * 1200;
                       break;
                   }
           }
       }
       
       private void DeleteLine(int i)
       {
           for (int j = i; j > 0; j--)
           {
               for (int k = 0; k < CMax; k++)
               {
                   _matrix[j, k].Status = _matrix[j - 1, k].Status;
                   _matrix[j, k].CoLor = _matrix[j - 1, k].CoLor;
               }
           }
       }
    }
}
